package com.ymx.darling.executor.mapping.result;

import com.ymx.darling.bean.entity.BeanInfo;
import com.ymx.darling.bean.entity.BeanInfoManager;
import com.ymx.darling.bean.entity.FieldInfo;
import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.executor.mapping.metadata.MetaData;
import com.ymx.darling.executor.mapping.metadata.MetaDataManager;
import com.ymx.darling.type.TypeHandler;
import com.ymx.darling.util.CollectionUtil;

import java.util.*;

/**
 * 创建自动映射的ResultMap
 * @author 爱Java的小于
 */
public class AutoResultMapBuilder implements ResultMapBuilder{

    public ResultMap buildResultMap(Statement statement, LinkedHashSet<MetaData> metaDataList) {
        return this.createResultMap(statement.getModule(), metaDataList);
    }


    /**
     * 根据实体类型自动构建ResultMap
     * @param module 根据实体类嵌套结构构建ResultMap
     * @param metaDataList 结果集元数据
     * @return ResultMap
     */
    private ResultMap createResultMap(Class<?> module, LinkedHashSet<MetaData> metaDataList) {
        // 构建实体类与结果集的映射关系
        BeanInfo beanInfo = BeanInfoManager.getBeanInfo(module);
        ResultMap resultMap = this.createSimpleResultMap(beanInfo, metaDataList);
        if (Objects.nonNull(resultMap)) {
            // 判断元数据没有匹配完那么继续匹配级联字段
            if (CollectionUtil.notEmpty(metaDataList)) {
                beanInfo.getRelationFieldInfoList().forEach(nestedFieldInfo -> {
                    // 自动嵌套映射实体字段时忽略未注册的类型
                    if (BeanInfoManager.isRegister(nestedFieldInfo.getFieldType())) {
                        ResultMap nestedResultMap = this.createResultMap(nestedFieldInfo.getFieldType(), metaDataList);
                        // 判断存在匹配的字段字段则构建级联映射
                        if (Objects.nonNull(nestedResultMap)) {
                            nestedResultMap.setField(nestedFieldInfo.getField());
                            resultMap.addResultMaps(nestedResultMap, nestedFieldInfo.getAssociationType());
                        }
                    }
                });
            }
        }
        // 返回ResultMap
        return resultMap;
    }


    /**
     * 根据metaDataList构建简单的ResultMap
     * @param beanInfo beanInfo
     * @param metaDataList metaDataList
     * @return ResultMap
     */
    private ResultMap createSimpleResultMap(BeanInfo beanInfo, LinkedHashSet<MetaData> metaDataList) {
        if (CollectionUtil.notEmpty(metaDataList)) {
            // 将实体类字段与结果集元数据按照名称进行匹配
            List<MetaData> entityMetaDataList = this.matchingFieldMapping(beanInfo, metaDataList);
            // 没有匹配到元数据返回null
            if (CollectionUtil.notEmpty(entityMetaDataList)) {
                // 构建一个新节点
                ResultMap resultMap = new ResultMap();
                // 设置类型映射器
                MetaDataManager.addTypeHandler(entityMetaDataList);
                resultMap.setBeanInfo(beanInfo);
                resultMap.setModule(beanInfo.getModule());
                resultMap.setMetaDataList(entityMetaDataList);
                //设置结果集中的id字段
                FieldInfo idFieldInfo = beanInfo.getIdColumnInfo();
                String idName = Objects.nonNull(idFieldInfo) ? idFieldInfo.getColumn() : null;
                for (MetaData md : entityMetaDataList) {
                    if (md.getName().equals(idName)) {
                        resultMap.setIdMetaData(md);
                        break;
                    }
                }
                return resultMap;
            }
        }
        return null;
    }


    /**
     * 自动匹配结果集与javaBean的字段信息 并为MetaData添加Field实例
     *
     * @param beanInfo beanInfo
     * @param metaDataList 元数据信息List 会从次list中移除匹配成功的MetaData
     * @return 返回beanInfo的MetaData
     */
    public List<MetaData> matchingFieldMapping(BeanInfo beanInfo, LinkedHashSet<MetaData> metaDataList){
        //保存匹配的结果集元数据列表
        List<MetaData> newMetaDataList = new ArrayList<>();
        Set<MetaData> removeMetaDataSet = new HashSet<>();
        Map<String, FieldInfo> simpleColumnMap = beanInfo.getSimpleColumnMap();

        for (MetaData metaData : metaDataList) {
            String resultColumnName = metaData.getName();
            // 处理结果集字段中包含$ 例如 table$column
            if (metaData.hasAsTable()) {
                BeanInfo asTableBeaInfo = BeanInfoManager.getTableBeanInfo(metaData.getAsTable());
                if (!beanInfo.isBeanInfoTableNameEqual(asTableBeaInfo)) {
                    resultColumnName = null;
                }
            }
            //如果指定字段信息匹配javaBean中的属性信息 那么为MetaData添加Field实例
            FieldInfo fieldInfo = simpleColumnMap.get(resultColumnName);
            if (Objects.nonNull(fieldInfo)){
                metaData.setField(fieldInfo.getField());
                // 判断用户配置了自定义类型转换器
                TypeHandler<?> typeHandler = fieldInfo.getTypeHandler();
                if (Objects.nonNull(typeHandler)) {
                    metaData.setTypeHandler(typeHandler);
                }
                newMetaDataList.add(metaData);
                removeMetaDataSet.add(metaData);
            }
        }
        // 移除匹配过的元数据
        removeMetaDataSet.forEach(metaDataList::remove);

        return newMetaDataList;
    }
}
